package org.dtrd.modules.record.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.dtrd.common.util.DateUtils;
import org.dtrd.config.system.Constant;
import org.dtrd.config.system.Constant.RecordType;
import org.dtrd.modules.achievement.service.IDtrdEntRdSigninRecordService;
import org.dtrd.modules.record.entity.bean.*;
import org.dtrd.modules.record.entity.po.DtrdEntRdSigninSleep;
import org.dtrd.modules.record.mapper.DtrdEntRdSigninSleepMapper;
import org.dtrd.modules.record.service.ISleepRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author QR
 * @since 2021-11-05
 */
@Service
@DS("multi-datasource1")
@Slf4j
public class SleepRecordRecordServiceImpl extends ServiceImpl<DtrdEntRdSigninSleepMapper, DtrdEntRdSigninSleep> implements ISleepRecordService {

    @Autowired
    private IDtrdEntRdSigninRecordService signinRecordService;

    @Override
    public DtrdEntRdSigninSleep transformRecord(CheckinRecord record) {
        DtrdEntRdSigninSleep dt = new DtrdEntRdSigninSleep().init();
        dt.setPatientId(record.getPatientId());
        dt.setRecordTime(parseStringAsDateTime(record.getRecordTime()));
        dt.setRecordDate(parseStringAsDate(record.getRecordTime()));
        dt.setSleepRemark(record.getRemark());
        dt.setSleepDescribe(record.getSleepDesc());
        dt.setSleepStatus(record.getSleep());
        dt.setSleepRemark(record.getRemark());
        return dt;
    }

    @Override
    public CheckinRecord transformPO(DtrdEntRdSigninSleep po) {
        CheckinRecord record = new CheckinRecord();
        record.setRecordTime(DateUtils.formatTime(po.getRecordTime()));
        record.setRecordTimeHm(DateUtils.formatShortTime(po.getRecordTime()));
        record.setDataId(po.getDataId());
        record.setPatientId(po.getPatientId());
        record.setRecordType(Constant.RecordType.SLEEP.getType());
        record.setRecordTypeName(Constant.RecordType.SLEEP.getName());
        record.setRemark(po.getSleepRemark());
        record.setSleepDesc(po.getSleepDescribe());
        record.setSleep(po.getSleepStatus());
        return record;
    }

    @Override
    public LambdaQueryWrapper<DtrdEntRdSigninSleep> generateSelectRecordByDateQuery(Integer patientId, String date, Integer subType) {
        return Wrappers.lambdaQuery(DtrdEntRdSigninSleep.class)
                .eq(DtrdEntRdSigninSleep::getPatientId, patientId)
                .eq(DtrdEntRdSigninSleep::getRecordDate, date);
    }

    @Override
    public boolean saveOrUpdateSleepRecord(SleepBean sleepBean) {
        DtrdEntRdSigninSleep po = new DtrdEntRdSigninSleep();
        if (sleepBean.getDataId() == null) {
            po = po.init();
        }
        po = po.parseFromDTO(sleepBean);
        LambdaUpdateWrapper<DtrdEntRdSigninSleep> wrapper = Wrappers.lambdaUpdate(DtrdEntRdSigninSleep.class)
                .eq(DtrdEntRdSigninSleep::getPatientId, sleepBean.getPatientId())
                .eq(DtrdEntRdSigninSleep::getRecordDate, po.getRecordDate());
        boolean result = saveOrUpdate(po, wrapper);
        log.info("SleepRecordRecordServiceImpl.saveOrUpdateSleepRecord.[sleepBean] afdter save patientId=" + po.getPatientId() + "; result=" + result + "; dataId=" + po.getDataId());
        if (po.getDataId() == null) {
            po = getOne(wrapper);
        }
        // 补充打卡
        signinRecordService.saveSigninRecord(po.getDataId(), 0, mapper ->
                mapper.apply(sleepBean.getPatientId())
                        .withRecordType(RecordType.SLEEP.getType())
                        .withRecordValue(sleepBean.getSleepStatus()+"")
                        .withRecordTime(sleepBean.getRecordTime())
                        .withRemark(sleepBean.getSleepRemark())
                        .withImages(sleepBean.getRecordPhoto())
                        .build()
        );
//        Date recordDate = newRecord.getRecordDate();
//        DtrdEntRdSigninSleep po = getOne(wrapper);
//        signinRecordService.saveSigninRecord(po.getDataId(), sleepBean.getPatientId(),
//                Constant.RecordType.SLEEP.getType(), 0,
//                DateUtils.formatDate(recordDate, DateUtils.date_sdf.get().toPattern()));
        return result;
    }

    @Override
    public SleepInfo getSleepRecordListByDateRange(Integer patientId, Integer pageNum, Integer pageSize, String startDate, String endDate) {
        SleepInfo sleepInfo = new SleepInfo();
        // 查询日期范围内的所有记录
        LambdaQueryWrapper<DtrdEntRdSigninSleep> queryWrapper = baseQueryWrapper()
                .eq(DtrdEntRdSigninSleep::getPatientId, patientId)
                .ge(DtrdEntRdSigninSleep::getRecordDate, startDate)
                .le(DtrdEntRdSigninSleep::getRecordDate, endDate)
                .orderByDesc(DtrdEntRdSigninSleep::getRecordTime);
        List<DtrdEntRdSigninSleep> sleepRecords = list(queryWrapper);
        // 没记录直接返回
        if (sleepRecords.size() == 0) {
            sleepInfo.setCount(0);
            sleepInfo.setTotalPage(0);
            return sleepInfo;
        }
        // 转换成 recordDate : sleepPo 的映射
        Map<Date, List<DtrdEntRdSigninSleep>> dateToSleepPo = sleepRecords.stream()
                .collect(Collectors.groupingBy(DtrdEntRdSigninSleep::getRecordDate));
        // 键值对的个数即分页记录的条数
        int count = dateToSleepPo.size();
        sleepInfo.setCount(count);
        // 设置每日睡眠记录的列表
        ArrayList<SleepDailyRecord> sleepDailyRecords = new ArrayList<>(count);
        Set<Date> dates = dateToSleepPo.keySet();
        for (Date date : dates) {
            SleepDailyRecord sleepDailyRecord = new SleepDailyRecord();
            List<DtrdEntRdSigninSleep> dateSleepRecord = dateToSleepPo.get(date);
            // 每天只有一条睡眠记录, 取列表里 createTime 最新的
            Optional<DtrdEntRdSigninSleep> newSleep = dateSleepRecord.stream()
                    .max(Comparator.comparing(DtrdEntRdSigninSleep::getCreateTime));
            newSleep.ifPresent(po -> {
                sleepDailyRecord.setRecordTime(DateUtils.formatDate(po.getRecordTime(), DateUtils.date_sdf.get().toPattern()));
                Integer sleepStatus = po.getSleepStatus();
                sleepDailyRecord.setSleepStatus(sleepStatus);
                sleepDailyRecord.setSleepDescribe(po.getSleepDescribe());
                Constant.SleepStatus status = Constant.SleepStatus.valueOf(sleepStatus);
                assert status != null;
                sleepDailyRecord.setSleepStatusText(status.getSleepStatusDesc());
                sleepDailyRecord.setSleepBean(new SleepBean(po));
            });
            sleepDailyRecords.add(sleepDailyRecord);
        }
        // 排序
        sleepDailyRecords.sort(Comparator.comparing(SleepDailyRecord::getRecordTime, Comparator.reverseOrder()));
        // 处理分页
        int pageStart = (pageNum - 1) * pageSize;
        List<SleepDailyRecord> resultRecords = sleepDailyRecords.stream().skip(pageStart).limit(pageSize).collect(Collectors.toList());
        sleepInfo.setRecordList(resultRecords);
        // 设置总页数
        Integer totalPage = count <= pageSize || pageSize <= 0 ? 1 : count / pageSize + 1;
        sleepInfo.setTotalPage(totalPage);
        return sleepInfo;
    }

    @Override
    public SleepChart getSleepChartByDateRange(Integer patientId, String startDate, String endDate) {
        baseQueryWrapper()
                .eq(DtrdEntRdSigninSleep::getPatientId, patientId)
                .ge(DtrdEntRdSigninSleep::getRecordDate, startDate)
                .le(DtrdEntRdSigninSleep::getRecordDate, endDate);
        return null;
    }

    private LambdaQueryWrapper<DtrdEntRdSigninSleep> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntRdSigninSleep.class).eq(DtrdEntRdSigninSleep::getIsDel, 0);
    }
}
